// DetectingFooRecursion.aj
//
// Informatics 102 Spring 2012
// Code Example
//
// This aspect detects recursive calls to the foo() method in the
// ClassWithRecursiveMethod class.  While it's not especially practical,
// for the purposes of demonstrating the difference between static and
// dynamic pointcuts, we'll separate the tasks of detecting direct
// recursion (where foo() calls foo()) from indirect recursion (where
// foo() calls bar() which calls foo()).  The direct recursion can be
// detected using static pointcuts -- those that depend only on what
// the program looks like -- while the indirect recursion will require
// us to use a dynamic pointcut, one that is dependent on the program's
// control flow.

public aspect DetectingFooRecursion
{
	// This pointcut captures calls to foo() that are made from within
	// the foo() method.  Note the use of a new primitive pointcut
	// called withincode().  The withincode() pointcut is similar to
	// the within() pointcut, except that it matches code within a
	// single method instead of code within a class.
	pointcut directlyRecursiveFooCalls():
		call(void ClassWithRecursiveMethod.foo(int))
		&& withincode(void ClassWithRecursiveMethod.foo(int));
	

	before():
		directlyRecursiveFooCalls()
	{
		System.out.println("DIRECT RECURSION!  foo() is directly calling foo()");
	}
	
	
	// This pointcut captures calls to foo() that are indirect.  Note
	// that we have to combine three primitive pointcuts:
	//
	// * Calls to the foo() method
	// * Those that are within the control flow of the body of the foo()
	//   method (which includes not only situations in which we're in
	//   the foo() method, but also when we're in a method called by
	//   foo(), or a method called by a method called by foo(), etc.)
	// * Points outside of the body of the foo() method
	//
	// Those three things together detect indirect recursion.
	pointcut indirectlyRecursiveFooCalls():
		call(void ClassWithRecursiveMethod.foo(int))
		&& cflow(execution(void ClassWithRecursiveMethod.foo(int)))
		&& !withincode(void ClassWithRecursiveMethod.foo(int));
	

	before():
		indirectlyRecursiveFooCalls()
	{
		System.out.println("INDIRECT RECURSION!  foo() is calling foo() indirectly");
	}
}


// Note that, as a practical matter, we usually don't care whether recursion
// is direct or indirect.  If we're interested in capturing recursion at all,
// it's usually a matter of capturing *any* recursion.  If you wanted to
// rewrite this aspect not to distinguish between direct and indirect
// recursion, you could replace its body with this instead:
//
//     pointcut recursiveFooCalls():
//         call(void ClassWithRecursiveMethod.foo(int))
//         && cflow(execution(void ClassWithRecursiveMethod.foo(int)));
//
//     before():
//         recursiveFooCalls()
//     {
//         System.out.println("RECURSION!");
//     }
